package com.will.txj.aj.security.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.will.txj.aj.global.utils.StringRedisUtil;
import com.will.txj.aj.security.service.IOauthClientDetailsService;
import com.will.txj.common.result.R;
import com.will.txj.common.result.RC;
import com.will.txj.common.security.AJUser;
import com.will.txj.common.security.OauthClientDetails;
import com.will.txj.common.utils.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author: wen-yi;
 * @date: 2021/12/4 23:38;
 * @Description:
 *
 */
@Slf4j
@RestController
@RequestMapping("auth")
@Api(tags = "登录控制层")
public class LoginController {
    @Autowired
    private StringRedisUtil stringRedisUtil;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IOauthClientDetailsService oauthClientDetailsService;
    @Value("${app.appId}")
    private String clientID;
    @Value("${app.secret}")
    private String clientSecret;
    @Value("${host.uri}")
    private String domain;

    @ApiOperation("获取des密钥")
    @PostMapping("getEncKey")
    public R getEncKey(HttpSession session){
        String key = stringRedisUtil.get(session.getId());
        if (StringUtil.isEmptyToString(key)){
            String key1 = StringUtil.getUUID();
            String key2 = StringUtil.getUUID();
            String key3 = StringUtil.getUUID();
            String encKey = key1 + "|" + key2 + "|" + key3;
            stringRedisUtil.setEx(session.getId(), encKey, 5, TimeUnit.MINUTES);
            return R.ok(encKey);
        }else return R.ok(key);
    }

    @ApiOperation("发起获取授权码请求")
    @SneakyThrows
    @GetMapping("authorize")
    public R toAuthorize(Authentication authentication,HttpServletResponse response){
        // 一体化应用先从redis中取授权token信息 已经授权则直接返回
        AJUser ajUser = (AJUser) authentication.getPrincipal();
        String token = stringRedisUtil.get("token-" + ajUser.getUsername());
        if (StringUtil.isEmptyToString(token)){
            log.info("未授权前往授权");
            // 获取应用的client信息
            try {
                OauthClientDetails client = oauthClientDetailsService.getById(clientID);
                log.info("获取用户凭证信息 -> clientId: {}, redirectUri: {}, scope: {}",
                        client.getClientId(),client.getWebServerRedirectUri(),client.getScope());
                response.sendRedirect("/oauth/authorize?response_type=code&client_id="+client.getClientId()+"&redirect_uri="+client.getWebServerRedirectUri()+"&scope="+client.getScope());
                return null;
            }catch (Exception e){
                return R.fail(RC.CLIENT_FAIL);
            }
        } else {
            log.info("已经在别处授权直接通过授权");
            response.sendRedirect("/pages/index");
            return null;
        }

    }

    @ApiOperation("获取授权码的回调")
    @ApiImplicitParam(name = "code",value = "授权码",required = true)
    @GetMapping("authorization")
    public R getCode(String code, Authentication authentication){
        log.info("获取的授权码 -> code: {}",code);
        AJUser ajUser = (AJUser) authentication.getPrincipal();
        OauthClientDetails client = oauthClientDetailsService.getById(clientID);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setBasicAuth(clientID, clientSecret);
        // 跳转认证
        String url = domain+"/oauth/token";
        //HashMap来作为body传递 解析转换不了，换成 MultiValueMap就ok了
        MultiValueMap params = new LinkedMultiValueMap();
        List<String> grantType = new ArrayList<>();grantType.add("authorization_code");
        params.put("grant_type",grantType);
        List<String> redirectUri = new ArrayList<>();redirectUri.add(client.getWebServerRedirectUri());
        params.put("redirect_uri",redirectUri);
        List<String> scope = new ArrayList<>();scope.add(client.getScope());
        params.put("scope",scope);
        List<String> codes = new ArrayList<>();codes.add(code);
        params.put("code",codes);
        Object result = restTemplate.postForObject(url, new HttpEntity<>(params, headers), Object.class);
        // 本机一体化设计的所以前端没做太多处理，这里就将jwt放入redis 本来该放入前端的请求头 但是我懒就不写 反正一体化程序只作为测试
        if (result!=null&&ajUser!=null){
            String token = JSONObject.toJSONString(result);
            stringRedisUtil.setEx("token-"+ajUser.getUsername(),token,10, TimeUnit.HOURS);
            return R.ok(result);
        }
        return R.fail(RC.GET_TOKEN_FAIL);
    }
}
